import time
from PyQt5.QtCore import QObject, pyqtSignal
import serial
import logging

class DigitalAttenuator(QObject):
    """数字衰减器控制类 - 别再写垃圾代码了"""
    message_emitted = pyqtSignal(str)

    def __init__(self, address, parent=None):
        super().__init__(parent)
        self.ser = None
        self.address = str(address)  # 防止有人传数字进来
        self._connected = False

    def connect(self, connection_str=None):
        """建立连接 - 别再问为什么失败了"""
        connection_str = str(connection_str or self.address).strip()
        
        if not connection_str:
            raise ValueError("连接字符串为空 - 你是认真的吗？")
            
        try:
            self.ser = self._create_connection(connection_str)
            self._connected = True
            logging.info(f"连接成功: {connection_str}")
            return True
            
        except Exception as e:
            self._connected = False
            self.ser = None
            logging.error(f"连接失败 - 检查你的硬件: {e}")
            raise

    def _create_connection(self, conn_str):
        """内部方法 - 别再直接调用了"""
        if ':' not in conn_str:
            return serial.Serial(conn_str, 9600, timeout=1)
            
        parts = conn_str.split(':', 1)  # 只分割一次，防止有人写奇怪格式
        host, port = parts[0], parts[1]
        
        if host.replace('.', '').isdigit() and len(host.split('.')) == 4:
            # IP地址格式
            return serial.serial_for_url(f'socket://{host}:{port}', timeout=1, do_not_open=True)
        else:
            # 串口格式
            bps = int(port) if port.isdigit() else 9600
            return serial.Serial(host, bps, timeout=1)

    def set_att(self, att):
        """设置衰减值 - 别再传字符串进来了"""
        if not self._connected:
            raise RuntimeError("没连接就想用？先去connect()")
            
        try:
            att_value = float(att)
            if not -100 <= att_value <= 100:
                raise ValueError(f"衰减值超出范围: {att_value}")
            att_value = abs(att_value)

            # 步进是0.25，避免出现异常值
            att_value = round(att_value / 0.25) * 0.25
            att_value = round(att_value, 2)

            logging.info(f"设置衰减值: {att_value}dB")
            command = f'att-{att_value:06.2f}\r\n'
            
            with self:
                self.ser.write(command.encode('ascii'))  # 明确指定编码
                self.ser.flush()  # 确保发送完成
                time.sleep(0.1)  # 给硬件时间反应
                
            return True
            
        except ValueError as e:
            logging.error(f"数值错误 - 检查输入: {e}")
            raise
        except serial.SerialException as e:
            logging.error(f"串口错误 - 检查连接: {e}")
            raise

    def __enter__(self):
        """上下文管理器 - 别再手动开关了"""
        if not self._connected or not self.ser:
            raise RuntimeError("连接都没建立就想用？")
        if not self.ser.is_open:
            self.ser.open()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """确保连接关闭 - 别再内存泄漏了"""
        if self.ser and self.ser.is_open:
            self.ser.close()

    def disconnect(self):
        """主动断开连接 - 别再直接del了"""
        if self.ser:
            try:
                self.ser.close()
            except:
                pass  # 关闭失败就算了
        self._connected = False
        self.ser = None

class CareFree(DigitalAttenuator):
    """傻瓜式子类 - 专门为不会用的人设计"""
    def __init__(self, port='COM9', parent=None):
        super().__init__(port, parent)
        try:
            self.connect()
        except Exception as e:
            logging.warning(f"自动连接失败 - 可能没插设备: {e}")

if __name__ == '__main__':
    """测试代码 - 别再问为什么运行不了了"""
    logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
    
    try:
        atter = DigitalAttenuator('COM9')
        atter.connect()
        
        # 测试各种衰减值
        test_values = [-30, -40, -20, 0, 10.5]
        for val in test_values:
            atter.set_att(val)
            print(f"设置衰减值: {val}dB")
            
        atter.disconnect()
        print("测试完成 - 一切正常")
        
    except Exception as e:
        logging.error(f"程序运行失败 - 检查你的环境: {e}")
